#include <Arduino.h>
#include <NimBLEDevice.h>
#define LED_PIN 2
#define HR_UP 16
#define HR_DOWN 17
// 心率 定义服务 UUID 和特征值 UUID
#define HEART_RATE_SERVICE_UUID "180D"
#define HEART_RATE_MEASUREMENT_UUID "2A37"
NimBLECharacteristic* pCharacteristic = nullptr;
bool deviceConnected = false;
constexpr unsigned long debounce_delay = 50;
// 心率当前值
volatile uint8_t hr = 130;
volatile bool hr_change = false;
volatile unsigned long last_interrupt_time = 0;
// 软件定时器
hw_timer_t* hw_timer_0 = NULL;

void led_off()
{
    digitalWrite(LED_PIN, LOW);
}

void notify()
{
    if (deviceConnected)
    {
        const uint8_t hrData[2] = {0x00, hr};
        pCharacteristic->setValue(hrData, 2);
        const bool notify = pCharacteristic->notify();
        if (notify)
        {
            Serial.print("hr notify ");
            Serial.println(hr);
            digitalWrite(LED_PIN, !digitalRead(LED_PIN));
            delay(50);
            digitalWrite(LED_PIN, !digitalRead(LED_PIN));
            delay(50);
        }
    }
    else
    {
        Serial.println("The Bluetooth device is not connected");
    }
}

class ServerCallbacks final : public NimBLEServerCallbacks
{
    void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override
    {
        deviceConnected = true;

        // 关闭定时器
        timerAlarmDisable(hw_timer_0);

        led_off();
    };

    void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override
    {
        deviceConnected = false;

        // 启动定时器
        timerAlarmEnable(hw_timer_0);

        NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
        pAdvertising->start();
    }
} serverCallbacks;

// 按键消抖逻辑
int debounce()
{
    int res = 0;
    unsigned long current_time = millis();
    if (current_time - last_interrupt_time > debounce_delay)
    {
        res = 1;
    }
    last_interrupt_time = current_time;
    return res;
}

void hr_up_handler()
{
    if (debounce())
    {
        if (hr == 255)
        {
            return;
        }
        hr++;
        hr_change = true;
    }
}

void hr_down_handler()
{
    if (debounce())
    {
        if (hr == 1)
        {
            return;
        }
        hr--;
        hr_change = true;
    }
}

// 定时器中断服务函数
void switch_led_timer_interrupt()
{
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
}

void setup()
{
    Serial.begin(9600);
    pinMode(LED_PIN, OUTPUT);
    pinMode(HR_UP, INPUT_PULLDOWN);
    pinMode(HR_DOWN, INPUT_PULLDOWN);

    // 初始化硬件定时器0（TIMER_0，分频系数80，向上计数）
    hw_timer_0 = timerBegin(0, 80, true); // 80分频 → 1MHz时钟（ESP32主频80MHz）
    timerAttachInterrupt(hw_timer_0, &switch_led_timer_interrupt, true);
    //绑定中断函数
    timerAlarmWrite(hw_timer_0, 100000, true); // 100ms触发一次

    NimBLEDevice::init("心率模拟器");

    NimBLEServer* pServer = NimBLEDevice::createServer();
    pServer->setCallbacks(&serverCallbacks);

    NimBLEService* pService = pServer->createService(NimBLEUUID(HEART_RATE_SERVICE_UUID));
    pCharacteristic = pService->createCharacteristic(NimBLEUUID(HEART_RATE_MEASUREMENT_UUID),
                                                     NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
    pService->start();

    NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
    pAdvertising->setName("心率模拟器01");
    pAdvertising->addServiceUUID(pService->getUUID());
    pAdvertising->start();
    // 启动定时器
    timerAlarmEnable(hw_timer_0);

    // 外部中断
    attachInterrupt(digitalPinToInterrupt(HR_UP), hr_up_handler, FALLING);
    attachInterrupt(digitalPinToInterrupt(HR_DOWN), hr_down_handler, FALLING);
}

void loop()
{
    if (hr_change)
    {
        Serial.print("hr set ");
        Serial.println(hr);
        hr_change = false;
    }
    notify();
    delay(900);
}
